import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import cv2 as cv
# import time

class main_interface(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(100, 100, 600, 400)
        self.setWindowTitle("主界面")

        # 创建主布局
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(20, 20, 20, 20)  # 设置布局的边距
        main_layout.setSpacing(20)  # 设置布局内部件之间的间距

        # 图像处理标题部分，设置在顶部与中部之间
        self.image_label = QLabel("图像处理", self)
        self.image_label.setAlignment(Qt.AlignCenter)
        self.image_label.setStyleSheet("font-size: 32px; font-weight: bold; margin-top: 60px;")
        main_layout.addWidget(self.image_label)

        # 添加一个伸缩空间，使按钮与标题之间有适当的距离
        main_layout.addStretch(1)

        # 按钮部分 - 使用垂直布局
        button_layout = QVBoxLayout()
        button_layout.setSpacing(10)  # 设置按钮之间的间距

        # 启动按钮
        self.jump_button = QPushButton("启动！", self)
        self.jump_button.clicked.connect(self.functional_interface)
        self.jump_button.setToolTip("点击进入图像处理程序")
        self.jump_button.setMinimumSize(100, 60)
        button_layout.addWidget(self.jump_button)

        # 制作人员按钮
        self.credits_button = QPushButton("制作人员", self)
        self.credits_button.clicked.connect(self.show_credits)
        self.credits_button.setToolTip("点击查看制作人员名单")
        self.credits_button.setStyleSheet("font-size:16px;padding:10px 20px")
        self.credits_button.setMinimumSize(100, 60)
        button_layout.addWidget(self.credits_button)

        # 将按钮布局添加到主布局中
        button_layout.setSpacing(20)  # 设置按钮之间的间距
        main_layout.addLayout(button_layout)

        spacer_bottom = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        main_layout.addItem(spacer_bottom)

        # 时间标签部分
        self.time_label = QLabel(self)
        self.update_time()  # 初始化时间显示

        # 定时器来更新时间
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_time)
        self.timer.start(1000)  # 每秒更新一次

        # 添加时间标签到底部
        time_layout = QHBoxLayout()
        time_layout.addWidget(self.time_label)
        time_layout.addStretch(1)  # 使用stretch将时间标签推到右侧

        # 添加时间布局
        main_layout.addLayout(time_layout)

        # 设置最终的布局
        self.setLayout(main_layout)
        self.show()


    def closeEvent(self, event):
        reply = QMessageBox.question(self, '退出', '是否关闭主界面？',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        if reply == QMessageBox.Yes:
            event.accept()  # 确认退出，关闭窗口
        else:
            event.ignore()  # 取消退出，不关闭窗口

    def show_credits(self):
        # 显示制作人员信息的对话框
        credits_dialog = QDialog(self)
        credits_dialog.setWindowTitle("制作人员")
        credits_layout = QVBoxLayout()

        credits_label = QLabel("制作人员列表：\n- 开发者A\n- 开发者B\n- 设计师C")
        credits_layout.addWidget(credits_label)

        credits_dialog.setLayout(credits_layout)
        credits_dialog.resize(300, 200)  # 设置对话框的大小
        credits_dialog.exec_()  # 显示对话框并等待用户关闭它

    def update_time(self):
        self.time_label.setText(f"当前时间: "
                f"{QTime.currentTime().toString('hh:mm:ss')}")

    def functional_interface(self):
        global fun_interface, picshow1, picshow2
        fun_interface = QDialog(self)
        fun_interface.setGeometry(300, 200, 1000, 600)
        fun_interface.setWindowTitle("功能界面")
        fun_interface.setWindowModality(Qt.ApplicationModal)

        # 设置子界面的背景图片
        background_image_path = "D:/python/python_study/test.png"  # 确保图片路径正确
        fun_interface.setStyleSheet(f"""
            QDialog {{
                background-image: url({background_image_path});
                background-position: center;
                background-repeat: no-repeat;
                background-size: cover;  /* 根据需要调整背景图片的大小 */
            }}
        """)

        picshow1 = QLabel("原图展示",fun_interface)
        picshow1.setGeometry(50,50,350,350)
        picshow1.setStyleSheet('border-width: 2px;border-style: solid;border-color: rgb(0, 0, 0)')
        picshow1.setAlignment(Qt.AlignCenter)
        picshow1.setToolTip("这里展示原图")

        picshow2 = QLabel("图像显示",fun_interface)
        picshow2.setGeometry(450,50,350,350)
        picshow2.setStyleSheet('border-width: 2px;border-style: solid;border-color: rgb(0, 0, 0)')
        picshow2.setAlignment(Qt.AlignCenter)
        picshow2.setToolTip("这里展示修图")

        groupBox_slider = QGroupBox('阈值调整',fun_interface)
        groupBox_slider.setGeometry(850,120,50,280)

        global slider
        slider=QSlider(Qt.Vertical,fun_interface)
        slider.setGeometry(865, 135, 20, 250)
        slider.setMinimum(0)  # 滑动条的最小值为0
        slider.setMaximum(255)  # 滑动条的最大值为255
        slider.setSingleStep(25)  # 滑动条的一步步长为25
        slider.setValue(150)  # 滑动条的初始值为150
        slider.setTickPosition(QSlider.TicksAbove)  # 滑动条的刻度位置在上边
        slider.setTickInterval(25)

        global select
        select=QComboBox(fun_interface)
        select.setGeometry(850,420,130,60)
        select.addItems(["   -请选择-","   -基础功能-","   -其他功能-"])
        select.currentIndexChanged.connect(self.button_change)

        global button_read
        button_read = QPushButton("读取图片", fun_interface)
        button_read.setGeometry(850, 50, 130, 50)
        button_read.setToolTip("这是读取图片的按钮")
        button_read.clicked.connect(self.open)


        global button_gray
        button_gray = QPushButton("灰度化", fun_interface)
        button_gray.setGeometry(50, 450, 130, 75)
        button_gray.setToolTip("这是灰度化的按钮")
        button_gray.hide()
        button_gray.setEnabled(False)
        button_gray.clicked.connect(self.gray)

        # global button_sharpen
        # button_sharpen = QPushButton("锐化", fun_interface)
        # button_sharpen.setGeometry(50, 450, 130, 75)
        # button_sharpen.setToolTip("这是锐化的按钮")
        # button_sharpen.hide()
        # button_sharpen.setEnabled(False)
        # button_sharpen.clicked.connect(fun_interface.sharpen)

        global button_tp
        button_tp = QPushButton("二值化", fun_interface)
        button_tp.setGeometry(225, 450, 130, 75)
        button_tp.setToolTip("这是二值化的按钮")
        button_tp.setEnabled(True)
        button_tp.hide()
        button_tp.clicked.connect(self.two_part)
        button_tp.setEnabled(False)  # 设置该按钮初始时不可用

        global button_corrosion
        button_corrosion = QPushButton("腐蚀", fun_interface)
        button_corrosion.setGeometry(225, 525, 130, 75)
        button_corrosion.setToolTip("这是腐蚀的按钮")
        button_corrosion.hide()
        button_corrosion.setEnabled(False)
        button_corrosion.clicked.connect(self.erosion)

        global button_cs
        button_cs = QPushButton("边缘检测", fun_interface)
        button_cs.setGeometry(400, 450, 130, 75)
        button_cs.setToolTip("这是边缘检测的按钮")
        button_cs.setEnabled(True)
        button_cs.hide()
        button_cs.clicked.connect(self.canny_show)
        button_cs.setEnabled(False)  # 设置该按钮初始时不可用

        global button_swell
        button_swell = QPushButton("膨胀", fun_interface)
        button_swell.setGeometry(400, 525, 130, 75)
        button_swell.setToolTip("这是膨胀的按钮")
        button_swell.hide()
        button_swell.setEnabled(False)
        button_swell.clicked.connect(self.swell)

        global button_fd
        button_fd = QPushButton("人脸检测", fun_interface)
        button_fd.setGeometry(575,450, 130, 75)
        button_fd.setToolTip("这是人脸检测的按钮")
        button_fd.hide()
        button_fd.clicked.connect(self.face_detect)
        button_fd.setEnabled(False)  # 设置该按钮初始时不可用

        global button_fp
        button_fp = QPushButton("模糊处理", fun_interface)
        button_fp.setGeometry(575, 525, 130, 75)
        button_fp.setToolTip("这是模糊处理的按钮")
        button_fp.hide()
        button_fp.clicked.connect(self.fuzzy_processing)
        button_fp.setEnabled(False)

        fun_interface.exec_()

    def open(self):
        global openfile_name
        # openfile_name这个变量获取打开文件的信息，实际含有两个数值，openfile_name[0]为文件路径，openfile_name[1]为文件类型
        openfile_name = QFileDialog.getOpenFileName(self, '请选择文件', 'C:\\photo',
                                                    'JPG(*.jpg);;All files(*)')
        # 弹出打开文件的窗口，设置窗口题目，打开文件的默认路径，以及打开文件的类型选择
        # print(openfile_name[0])
        # print(openfile_name[1])
        # 进行判断，如果打开的是JPG文件则将图片显示在标签中
        if openfile_name[1] == 'JPG(*.jpg)':
            picshow1.setPixmap(QPixmap(openfile_name[0]))  # label_main中显示选择的图片
            picshow1.setScaledContents(True)  # 设置标签中图片自适应标签大小
            button_gray.setEnabled(True)  # 使button2按钮可用
            button_fd.setEnabled(True)
            button_fp.setEnabled(True)
            button_corrosion.setEnabled(True)
            picshow2.setPixmap(QPixmap(""))
        else:
            picshow1.setPixmap(QPixmap(""))
            picshow1.setText("图像显示区域")

    def gray(self):
        global img_gray
        img = cv.imread(openfile_name[0])  # 读取原图，路径不能有中文
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 将原图灰度化
        img2 = cv.cvtColor(img_gray, cv.COLOR_BGR2RGB)  # 从该行开始的下三行为图片通道格式的转换，为了让opencv处理过的图片能够在pyqt5设置的界面上显示出来
        qt_img = QImage(img2[:], img2.shape[1], img2.shape[0], img2.shape[1]*3, QImage.Format_RGB888)
        img_out = QPixmap(qt_img).scaled(picshow2.width(), picshow2.height())
        picshow2.setPixmap(img_out)  # 标签中显示处理后的图片
        button_tp.setEnabled(True)
        button_cs.setEnabled(True)

    def two_part(self):
        ret, threshold = cv.threshold(img_gray, slider.value(), 255, cv.THRESH_BINARY_INV)  # 二值化，其中阈值使用的是滑动条的当前数值slider.value()
        img2 = cv.cvtColor(threshold, cv.COLOR_BGR2RGB)
        qt_img = QImage(img2[:], img2.shape[1], img2.shape[0], img2.shape[1]*3, QImage.Format_RGB888)
        img_out = QPixmap(qt_img).scaled(picshow2.width(), picshow2.height())
        picshow2.setPixmap(img_out)

    def canny_show(self):
        img_gaussian = cv.GaussianBlur(img_gray, (3, 3), 0)  # 高斯平滑降噪
        if slider.value() > 150:
            canny = cv.Canny(img_gaussian, 50, slider.value())  # canny算子边缘检测
        else:
            canny = cv.Canny(img_gaussian, 50, 150)

        img2 = cv.cvtColor(canny, cv.COLOR_BGR2RGB)
        qt_img = QImage(img2[:], img2.shape[1], img2.shape[0], img2.shape[1]*3, QImage.Format_RGB888)
        img_out = QPixmap(qt_img).scaled(picshow2.width(), picshow2.height())
        picshow2.setPixmap(img_out)

    def face_detect(self):
        global num_face
        num_face = 0  # 设置人脸计数的变量
        img = cv.imread(openfile_name[0])
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        classifier = cv.CascadeClassifier("haarcascade_frontalface_default.xml")  # 因为使用相对路径，该xml文件必须要有且在py文件的同级目录下
        faceRects = classifier.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))
        if len(faceRects) > 0:
            for faceRect in faceRects:
                x, y, w, h = faceRect
                cv.rectangle(img, (x-10, y-10), (x+w+10, y+h+10), (0, 255, 0), 3)  # 使用绿色矩形线条框出人脸
                num_face = num_face+1

        img2 = cv.cvtColor(img, cv.COLOR_BGR2RGB)
        qt_img = QImage(img2[:], img2.shape[1], img2.shape[0], img2.shape[1]*3, QImage.Format_RGB888)
        img_out = QPixmap(qt_img).scaled(picshow2.width(), picshow2.height())
        picshow2.setPixmap(img_out)

    def erosion(self):
        if openfile_name[1] == 'JPG(*.jpg)':  # 确保有图片路径
            # 读取原始图像
            original_image = cv.imread(openfile_name[0])
            if original_image is None:
                print("Error: Could not read image.")
                return

            # 转换为灰度图像
            gray_image = cv.cvtColor(original_image, cv.COLOR_BGR2GRAY)

            # 应用二值化
            _, binary_image = cv.threshold(gray_image, 127, 255, cv.THRESH_BINARY)

            # 定义腐蚀的核（结构元素）
            kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

            # 应用腐蚀操作
            eroded_image = cv.erode(binary_image, kernel, iterations=1)

            # 将处理后的图像转换为QImage
            height, width = eroded_image.shape
            bytesPerLine = width
            qt_img = QImage(eroded_image.data, width, height, bytesPerLine, QImage.Format_Grayscale8)

            # 显示腐蚀后的图像
            eroded_pixmap = QPixmap.fromImage(qt_img)
            picshow2.setPixmap(eroded_pixmap.scaled(picshow2.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))

    def fuzzy_processing(self):
        if openfile_name[1] == 'JPG(*.jpg)':  # 确保有图片路径
            # 读取原始图像
            original_image = cv.imread(openfile_name[0])
            # 应用高斯模糊滤镜
            blurred_image = cv.GaussianBlur(original_image, (15, 15), 0)
            # 将处理后的图像转换为QImage
            height, width, channel = blurred_image.shape
            bytesPerLine = 3 * width
            qt_img = QImage(blurred_image.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped()
            # 显示模糊后的图像
            blurred_pixmap = QPixmap.fromImage(qt_img)
            # 缩放图片以精确匹配picshow2的大小
            picshow2.setPixmap(blurred_pixmap.scaled(picshow2.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation))

    def swell(self):
        global openfile_name, picshow1, picshow2
        if openfile_name[1] == 'JPG(*.jpg)':  # 确保有图片路径
            # 读取原始图像
            original_image = cv.imread(openfile_name[0])
            if original_image is None:
                print("Error: Could not read image.")
                return

            # 转换为灰度图像
            gray_image = cv.cvtColor(original_image, cv.COLOR_BGR2GRAY)

            # 应用二值化
            _, binary_image = cv.threshold(gray_image, 127, 255, cv.THRESH_BINARY)

            # 定义膨胀的核（结构元素）
            kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

            # 应用膨胀操作
            dilated_image = cv.dilate(binary_image, kernel, iterations=1)

            # 将处理后的图像转换为QImage
            height, width = dilated_image.shape
            bytesPerLine = width
            qt_img = QImage(dilated_image.data, width, height, bytesPerLine, QImage.Format_Grayscale8)

            # 创建QPixmap对象
            dilated_pixmap = QPixmap.fromImage(qt_img)

            # 缩放图片以精确匹配picshow2的大小
            picshow2.setPixmap(dilated_pixmap.scaled(picshow2.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation))

    def button_change(self, index):
        # 隐藏所有按钮
        button_gray.hide()
        button_tp.hide()
        button_corrosion.hide()
        button_swell.hide()
        button_cs.hide()
        button_fd.hide()
        button_fp.hide()

        # 根据选择的索引显示相应的按钮
        if index == 1:  # 基础功能
            button_gray.show()
            button_tp.show()
            button_corrosion.show()
            button_swell.show()
            button_cs.show()
        elif index == 2:  # 其他功能
            button_fd.show()
            button_fp.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = main_interface()
    win.show()
sys.exit(app.exec_())